﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using System.Reflection;
using System.Reflection.Emit;
using Microsoft.Win32.SafeHandles;
using Go;

namespace GoRpc
{
    static public partial class Rpc
    {
        public enum ExitCode
        {
            Undefined,
            LocalClose,
            RemoteClose,
            SessionClose,
            SocketClosed,
            KeepOvertime,
            RecvKeepOvertime,
            RecvBinOvertime,
            RecvBinError,
            SendBinOvertime,
            DataHeadError,
            ReplySerializeError,
            RequestSerializeError,
            ReplyDeserializeError,
            RequestDeserializeError,
        }

        public enum ReplyState
        {
            Fail,
            IsNull,
            Success,
            Stopped,
            NotFound,
            Overtime,
            Exception,
            IndexError,
            LocalCancel,
            RemoteCancel,
            ArgsTypeError,
            ArgsCountError,
            ResultTypeError,
            LocalSerializeError,
            RemoteSerializeError,
            LocalDeserializeError,
            RemoteDeserializeError,
        }

        class CastArgsException : Exception
        {
            public ReplyState state = ReplyState.ArgsTypeError;
        }

        const BindingFlags InstanceFlag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        static readonly object[] EmptyArgs = new object[0];

        static Func<object> CreateDefinedNew(Type type)
        {
            if (type.IsValueType)
            {
                return Expression.Lambda<Func<object>>(Expression.Convert(Expression.New(type), typeof(object))).Compile();
            }
            var methodName = $"DynamicNew {type.Name}";
            var dynamicMethod = new DynamicMethod(methodName, typeof(object), Type.EmptyTypes, typeof(Rpc).Module, true);
            var constructor = type.GetConstructor(InstanceFlag, null, Type.EmptyTypes, null);
            assert.check(constructor != null, "构造参数不匹配");
            var il = dynamicMethod.GetILGenerator();
            il.Emit(OpCodes.Newobj, constructor);
            il.Emit(OpCodes.Ret);
            return (Func<object>)dynamicMethod.CreateDelegate(typeof(Func<object>));
        }

        static Func<object, object[], object> CreateCall(MethodInfo methodInfo)
        {
            var objectType = methodInfo.DeclaringType;
            var returnType = methodInfo.ReturnType;
            var paramTypes = methodInfo.GetParameters();
            var methodName = $"DynamicCall {objectType.Name}.{methodInfo.Name}";
            var dynamicMethod = new DynamicMethod(methodName, typeof(object), new Type[] { typeof(object), typeof(object[]) }, typeof(Rpc).Module, true);
            var il = dynamicMethod.GetILGenerator();
            var locals = new LocalBuilder[paramTypes.Length];
            if (paramTypes.Length > 0)
            {
                il.BeginExceptionBlock();
                for (int i = 0; i < paramTypes.Length; i++)
                {
                    var parameterType = paramTypes[i].ParameterType;
                    locals[i] = il.DeclareLocal(parameterType);
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Ldc_I4, i);
                    il.Emit(OpCodes.Ldelem_Ref);
                    if (parameterType.IsValueType)
                    {
                        il.Emit(OpCodes.Dup);
                        var notNullLabel = il.DefineLabel();
                        il.Emit(OpCodes.Brtrue_S, notNullLabel);
                        il.Emit(OpCodes.Newobj, typeof(CastArgsException).GetConstructor(InstanceFlag, null, Type.EmptyTypes, null));
                        il.Emit(OpCodes.Throw);
                        il.MarkLabel(notNullLabel);
                        il.Emit(OpCodes.Unbox_Any, parameterType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Castclass, parameterType);
                    }
                    il.Emit(OpCodes.Stloc, locals[i]);
                }
                il.BeginCatchBlock(typeof(InvalidCastException));
                il.Emit(OpCodes.Pop);
                il.Emit(OpCodes.Newobj, typeof(CastArgsException).GetConstructor(InstanceFlag, null, Type.EmptyTypes, null));
                il.Emit(OpCodes.Throw);
                il.EndExceptionBlock();
            }
            if (!methodInfo.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(objectType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, objectType);
            }
            for (int i = 0; i < paramTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldloc, locals[i]);
            }
            il.Emit(methodInfo.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, methodInfo);
            if (returnType == typeof(void))
            {
                il.Emit(OpCodes.Ldnull);
            }
            else if (returnType.IsValueType)
            {
                il.Emit(OpCodes.Box, returnType);
            }
            il.Emit(OpCodes.Ret);
            return (Func<object, object[], object>)dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
        }

        static Func<object, object> CreateObjectGetter(FieldInfo fieldInfo)
        {
            var objectType = fieldInfo.DeclaringType;
            var fieldType = fieldInfo.FieldType;
            var methodName = $"DynamicGet {objectType.Name}.{fieldInfo.Name}";
            var dynamicMethod = new DynamicMethod(methodName, typeof(object), new Type[] { typeof(object) }, typeof(Rpc).Module, true);
            var il = dynamicMethod.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            if (!fieldInfo.IsStatic)
            {
                il.Emit(objectType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, objectType);
            }
            il.Emit(OpCodes.Ldfld, fieldInfo);
            if (fieldType.IsValueType)
            {
                il.Emit(OpCodes.Box, fieldType);
            }
            il.Emit(OpCodes.Ret);
            return (Func<object, object>)dynamicMethod.CreateDelegate(typeof(Func<object, object>));
        }

        static Action<object, object> CreateObjectSetter(FieldInfo fieldInfo)
        {
            var objectType = fieldInfo.DeclaringType;
            var fieldType = fieldInfo.FieldType;
            var methodName = $"DynamicSet {objectType.Name}.{fieldInfo.Name}";
            var dynamicMethod = new DynamicMethod(methodName, typeof(void), new Type[] { typeof(object), typeof(object) }, typeof(Rpc).Module, true);
            var il = dynamicMethod.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            if (!fieldInfo.IsStatic)
            {
                il.Emit(objectType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, objectType);
            }
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(fieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, fieldType);
            il.Emit(OpCodes.Stfld, fieldInfo);
            il.Emit(OpCodes.Ret);
            return (Action<object, object>)dynamicMethod.CreateDelegate(typeof(Action<object, object>));
        }

        static Func<object, object> CreateObjectGetter(MethodInfo methodInfo)
        {
            var objectType = methodInfo.DeclaringType;
            var propertyType = methodInfo.ReturnType;
            var methodName = $"DynamicGet {objectType.Name}.{methodInfo.Name}";
            var dynamicMethod = new DynamicMethod(methodName, typeof(object), new Type[] { typeof(object) }, typeof(Rpc).Module, true);
            var il = dynamicMethod.GetILGenerator();
            if (!methodInfo.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(objectType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, objectType);
            }
            il.Emit(OpCodes.Call, methodInfo);
            if (propertyType.IsValueType)
            {
                il.Emit(OpCodes.Box, propertyType);
            }
            il.Emit(OpCodes.Ret);
            return (Func<object, object>)dynamicMethod.CreateDelegate(typeof(Func<object, object>));
        }

        static Action<object, object> CreateObjectSetter(MethodInfo methodInfo)
        {
            var objectType = methodInfo.DeclaringType;
            var propertyType = methodInfo.GetParameters()[0].ParameterType;
            var methodName = $"DynamicSet {objectType.Name}.{methodInfo.Name}";
            var dynamicMethod = new DynamicMethod(methodName, typeof(void), new Type[] { typeof(object), typeof(object) }, typeof(Rpc).Module, true);
            var il = dynamicMethod.GetILGenerator();
            if (!methodInfo.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(objectType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, objectType);
            }
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(propertyType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, propertyType);
            il.Emit(OpCodes.Call, methodInfo);
            il.Emit(OpCodes.Ret);
            return (Action<object, object>)dynamicMethod.CreateDelegate(typeof(Action<object, object>));
        }

        public sealed class Methods
        {
            static public Delegate Cast(Action handler) => handler;
            static public Delegate Cast<T0>(Action<T0> handler) => handler;
            static public Delegate Cast<T0, T1>(Action<T0, T1> handler) => handler;
            static public Delegate Cast<T0, T1, T2>(Action<T0, T1, T2> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3>(Action<T0, T1, T2, T3> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4>(Action<T0, T1, T2, T3, T4> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5>(Action<T0, T1, T2, T3, T4, T5> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6>(Action<T0, T1, T2, T3, T4, T5, T6> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7>(Action<T0, T1, T2, T3, T4, T5, T6, T7> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler) => handler;

            static public Delegate Cast<R>(Func<R> handler) => handler;
            static public Delegate Cast<T0, R>(Func<T0, R> handler) => handler;
            static public Delegate Cast<T0, T1, R>(Func<T0, T1, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, R>(Func<T0, T1, T2, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, R>(Func<T0, T1, T2, T3, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, R>(Func<T0, T1, T2, T3, T4, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, R>(Func<T0, T1, T2, T3, T4, T5, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, R>(Func<T0, T1, T2, T3, T4, T5, T6, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R> handler) => handler;

            struct BindObjInfo
            {
                public int task;
                public Type[] argsType;
                public Func<object, object[], object> method;
                public Func<object, object[], object> valueTask;
                public Func<object, object[], object> getResult;
            }

            [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Field)]
            public sealed class AllowBind : Attribute
            {
                internal readonly bool getter;
                internal readonly bool setter;
                internal readonly string name;

                public AllowBind(string name = null, bool getter = true, bool setter = true)
                {
                    this.getter = getter;
                    this.setter = setter;
                    this.name = name;
                }
            }

            [ParamTuple("Name", true)]
            public struct Name
            {
                [ParamName("name")] internal string name;

                public Name(string name)
                {
                    this.name = name;
                }

                static public implicit operator string(Name rval)
                {
                    return rval.name;
                }

                static private unsafe void Fill(ref char* dst, char* src, int len, bool first)
                {
                    if (!first)
                    {
                        *(dst++) = '.';
                    }
                    for (int i = 0; i < len; i++)
                    {
                        *(dst++) = *(src + i);
                    }
                }

                static public unsafe string Concat(string s1, string s2)
                {
                    int l1 = s1.Length, l2 = s2.Length;
                    string result = new string('\0', l1 + l2 + 1);
                    fixed (char* dst_ = result)
                    {
                        char* dst = dst_;
                        fixed (char* src = s1) Fill(ref dst, src, l1, true);
                        fixed (char* src = s2) Fill(ref dst, src, l2, false);
                    }
                    return result;
                }

                static public unsafe string Concat(string s1, string s2, string s3)
                {
                    int l1 = s1.Length, l2 = s2.Length, l3 = s3.Length;
                    string result = new string('\0', l1 + l2 + l3 + 2);
                    fixed (char* dst_ = result)
                    {
                        char* dst = dst_;
                        fixed (char* src = s1) Fill(ref dst, src, l1, true);
                        fixed (char* src = s2) Fill(ref dst, src, l2, false);
                        fixed (char* src = s3) Fill(ref dst, src, l3, false);
                    }
                    return result;
                }

                static public unsafe string Concat(string s1, string s2, string s3, string s4)
                {
                    int l1 = s1.Length, l2 = s2.Length, l3 = s3.Length, l4 = s4.Length;
                    string result = new string('\0', l1 + l2 + l3 + l4 + 3);
                    fixed (char* dst_ = result)
                    {
                        char* dst = dst_;
                        fixed (char* src = s1) Fill(ref dst, src, l1, true);
                        fixed (char* src = s2) Fill(ref dst, src, l2, false);
                        fixed (char* src = s3) Fill(ref dst, src, l3, false);
                        fixed (char* src = s4) Fill(ref dst, src, l4, false);
                    }
                    return result;
                }
            }

            struct DelegateInfo
            {
                public Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler;
            }

            class ClassInfo
            {
                public bool isStatic;
                public bool isAllowBind;
                public int arrayDim;
                public Type fieldType;
                public Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler;
            }

            static long _nameid = DateTime.Now.Ticks;
            static ConcurrentDictionary<Type, DelegateInfo> _delegateMap = new ConcurrentDictionary<Type, DelegateInfo>();
            static ConcurrentDictionary<Type, Dictionary<string, ClassInfo>> _classsMap = new ConcurrentDictionary<Type, Dictionary<string, ClassInfo>>();
            ConcurrentDictionary<string, tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand>> _methodsMap =
                new ConcurrentDictionary<string, tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand>>();
            ConcurrentDictionary<string, LinkedList<string>> _classMethods = new ConcurrentDictionary<string, LinkedList<string>>();

            static public Name GenName
            {
                get
                {
                    return new Name(Interlocked.Increment(ref _nameid).ToString("X16"));
                }
            }

            static public bool CheckName(string name)
            {
                if (string.IsNullOrEmpty(name))
                {
                    return false;
                }
                for (int i = 0; i < name.Length; i++)
                {
                    char c = name[i];
                    if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_')))
                    {
                        return false;
                    }
                }
                return true;
            }

            public void Bind(string name, Action handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0>(string name, Action<T0> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1>(string name, Action<T0, T1> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2>(string name, Action<T0, T1, T2> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3>(string name, Action<T0, T1, T2, T3> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4>(string name, Action<T0, T1, T2, T3, T4> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5>(string name, Action<T0, T1, T2, T3, T4, T5> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6>(string name, Action<T0, T1, T2, T3, T4, T5, T6> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(string name, Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);

            public void Bind<R>(string name, Func<R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, R>(string name, Func<T0, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, R>(string name, Func<T0, T1, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, R>(string name, Func<T0, T1, T2, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, R>(string name, Func<T0, T1, T2, T3, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, R>(string name, Func<T0, T1, T2, T3, T4, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, R>(string name, Func<T0, T1, T2, T3, T4, T5, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(string name, Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler, shared_strand runStrand = null) => Bind(name, (Delegate)handler, runStrand);
            public void Bind(string name, Delegate handler, shared_strand runStrand = null) => Bind(name, handler, null, null, runStrand);

            internal void Bind(string name, Delegate handler, wait_group stopWg, wait_group endWg, shared_strand runStrand)
            {
                if (!CheckName(name))
                {
                    assert.check(false, $"Bind 命名错误 {name}");
                    return;
                }
                DelegateInfo delegateInfo = GetDelegateInfo(handler.GetType());
                Add(name, (_1, _2) => delegateInfo.handler(handler, stopWg, endWg, _1, _2), runStrand);
            }

            static private DelegateInfo GetDelegateInfo(Type type)
            {
                if (_delegateMap.TryGetValue(type, out var delegateInfo))
                {
                    return delegateInfo;
                }
                MethodInfo method = type.GetMethod("Invoke");
                BindObjInfo methodInfo = new BindObjInfo { task = 0 };
                methodInfo.argsType = Array.ConvertAll(method.GetParameters(), (ParameterInfo v) => v.ParameterType);
                methodInfo.method = CreateCall(method);
                Type returnType = method.ReturnType;
                if (returnType.IsGenericType)
                {
                    Type genericType = returnType.GetGenericTypeDefinition();
                    if (typeof(Task<>) == genericType)
                    {
                        methodInfo.task = 1;
                        methodInfo.getResult = CreateCall(returnType.GetMethod("get_Result"));
                    }
                    else if (typeof(ValueTask<>) == genericType)
                    {
                        methodInfo.task = 2;
                        methodInfo.valueTask = CreateCall(returnType.GetMethod("AsTask"));
                        methodInfo.getResult = CreateCall(returnType.GetMethod("get_Result"));
                    }
                }
                else if (typeof(Task) == returnType)
                {
                    methodInfo.task = 3;
                }
                else if (typeof(ValueTask) == returnType)
                {
                    methodInfo.task = 4;
                    methodInfo.valueTask = CreateCall(returnType.GetMethod("AsTask"));
                }
                delegateInfo = new DelegateInfo();
                delegateInfo.handler = async delegate (object handler, wait_group stopWg, wait_group endWg, async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    if (null != endWg && endWg.cancel)
                    {
                        return;
                    }
                    if (methodInfo.argsType.Length != args.Length)
                    {
                        resWrap.value2 = ReplyState.ArgsCountError;
                        return;
                    }
                    wait_group.cancel_token cancelToken = default;
                    try
                    {
                        if (null != endWg)
                        {
                            endWg.add();
                            if (endWg.cancel)
                            {
                                return;
                            }
                        }
                        if (null != stopWg)
                        {
                            generator self = generator.self;
                            cancelToken = stopWg.async_wait(() => self.stop());
                        }
                        object result = methodInfo.method(handler, args);
                        switch (methodInfo.task)
                        {
                            case 0:
                                {
                                    resWrap.value1 = result;
                                }
                                break;
                            case 1:
                                {
                                    Task task = (Task)result;
                                    if (null != task)
                                    {
                                        await task;
                                        resWrap.value1 = methodInfo.getResult(task, null);
                                    }
                                }
                                break;
                            case 2:
                                {
                                    Task task = (Task)methodInfo.valueTask(result, null);
                                    if (null != task)
                                    {
                                        await task;
                                    }
                                    resWrap.value1 = methodInfo.getResult(result, null);
                                }
                                break;
                            case 3:
                                {
                                    Task task = (Task)result;
                                    if (null != task)
                                    {
                                        await task;
                                    }
                                }
                                break;
                            case 4:
                                {
                                    Task task = (Task)methodInfo.valueTask(result, null);
                                    if (null != task)
                                    {
                                        await task;
                                    }
                                }
                                break;
                        }
                    }
                    catch (CastArgsException)
                    {
                        resWrap.value2 = ReplyState.ArgsTypeError;
                    }
                    finally
                    {
                        stopWg?.cancel_wait(cancelToken);
                        endWg?.done();
                    }
                };
                _delegateMap.TryAdd(type, delegateInfo);
                return delegateInfo;
            }

            public void BindStatic(string name, Type type, shared_strand runStrand = null)
            {
                BindClass(name, type, null, false, null, null, runStrand);
            }

            public void BindStatic<T>(string name, shared_strand runStrand = null)
            {
                BindClass(name, typeof(T), null, false, null, null, runStrand);
            }

            public void BindObj<T>(string name, T obj, bool declaredOnly = true, shared_strand runStrand = null)
            {
                BindClass(name, typeof(T), obj, declaredOnly, null, null, runStrand);
            }

            static public void AssertName()
            {
                Assembly assembly = Assembly.GetCallingAssembly();
                Type[] allTypes = assembly.GetTypes();
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    GetClassInfo(type);
                }
            }

            static string ParseArray(string name, out int[][] indices)
            {
                indices = null;
                int l = name.Length;
                if (l < 4)
                {
                    return name;
                }
                if (name[l - 1] != ']')
                {
                    return name;
                }
                int leftIdx = name.IndexOf('[');
                if (!(leftIdx > 0 && leftIdx < l - 2))
                {
                    throw new CastArgsException { state = ReplyState.IndexError };
                }
                int dimCount = 0;
                for (int i = leftIdx; i < l; i++)
                {
                    if (name[i] == '[')
                    {
                        dimCount++;
                    }
                }
                indices = new int[dimCount][];
                dimCount = 0;
                for (int i = leftIdx; i < l; i++)
                {
                    char c = name[i];
                    if (c == '[')
                    {
                        int rankCount = 1;
                        for (int j = i + 1; j < l; j++)
                        {
                            c = name[j];
                            if (c == ']')
                            {
                                break;
                            }
                            if (c == ',')
                            {
                                rankCount++;
                            }
                            else if (!((c >= '0' && c <= '9') || c == ' ' || c == '\t' || c == '-'))
                            {
                                throw new CastArgsException { state = ReplyState.IndexError };
                            }
                        }
                        int[] index = indices[dimCount] = new int[rankCount];
                        rankCount = 0;
                        int number = 0;
                        bool neg = false;
                        bool num = false;
                        bool space = false;
                        for (i++; i < l; i++)
                        {
                            c = name[i];
                            if (c >= '0' && c <= '9')
                            {
                                if (space)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                number = number * 10 + (c - '0');
                                if (number < 0)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                num = true;
                            }
                            else if (c == ',' || c == ']')
                            {
                                if (!num)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                index[rankCount] = neg ? -number : number;
                                if (c == ']')
                                {
                                    break;
                                }
                                number = 0;
                                rankCount++;
                                neg = false;
                                num = false;
                                space = false;
                            }
                            else if (c == '-')
                            {
                                if (neg || num)
                                {
                                    throw new CastArgsException { state = ReplyState.IndexError };
                                }
                                neg = true;
                            }
                            else if (c == ' ' || c == '\t')
                            {
                                if (neg || num)
                                {
                                    space = true;
                                }
                            }
                        }
                        dimCount++;
                    }
                    else if (!(c == ' ' || c == '\t'))
                    {
                        throw new CastArgsException { state = ReplyState.IndexError };
                    }
                }
                return name.Substring(0, leftIdx);
            }

            internal unsafe void BindClass(string name, Type type, object obj, bool declaredOnly, wait_group stopWg, wait_group endWg, shared_strand runStrand)
            {
                if (!CheckName(name))
                {
                    assert.check(false, $"BindClass 命名错误 {name}");
                    return;
                }
                Dictionary<string, ClassInfo> classInfo = GetClassInfo(type);
                if (null == classInfo)
                {
                    assert.check(false, $"{name} 绑定了没有使用 AllowBind 特性的对象 {type.FullName}");
                    return;
                }
                Type itType = type;
                Dictionary<string, ClassInfo> itClassInfo = classInfo;
                LinkedList<string> names = new LinkedList<string>();
                do
                {
                    if (null != itClassInfo)
                    {
                        foreach (var item in itClassInfo)
                        {
                            if (null == obj && !item.Value.isStatic)
                            {
                                continue;
                            }
                            Add(names.AddLast(Name.Concat(name, item.Key)).Value, (_1, _2) => item.Value.handler(obj, stopWg, endWg, _1, _2), runStrand);
                        }
                        itClassInfo = null;
                    }
                    if (!declaredOnly)
                    {
                        itType = itType.BaseType;
                        if (null != itType)
                        {
                            itClassInfo = GetClassInfo(itType);
                        }
                    }
                    else
                    {
                        itType = null;
                    }
                } while (null != itClassInfo || null != itType);
                Add(names.AddLast(name).Value, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    object obj_ = obj;
                    Type type_ = type;
                    if (null == resWrap.value1)
                    {
                        resWrap.value2 = ReplyState.NotFound;
                        return generator.non_async();
                    }
                    string[] fields = (string[])resWrap.value1;
                    for (int i = 1; i < fields.Length - 1; i++)
                    {
                        string field_ = ParseArray(fields[i], out int[][] indices);
                        resWrap.value1 = null;
                        resWrap.value2 = ReplyState.Success;
                        ClassInfo field = CheckMethod(type_, null == obj_, string.Concat("get@", field_), declaredOnly);
                        field.handler(obj_, stopWg, endWg, resWrap, EmptyArgs);
                        if (resWrap.value2 != ReplyState.Success)
                        {
                            return generator.non_async();
                        }
                        obj_ = resWrap.value1;
                        type_ = field.fieldType;
                        if (null == indices)
                        {
                            continue;
                        }
                        if (field.arrayDim < indices.Length)
                        {
                            resWrap.value2 = ReplyState.NotFound;
                            return generator.non_async();
                        }
                        try
                        {
                            for (int j = 0; j < indices.Length; j++)
                            {
                                obj_ = GetValue((Array)obj_, indices[j]);
                            }
                        }
                        catch (IndexOutOfRangeException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (ArgumentException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (CastArgsException ec)
                        {
                            resWrap.value2 = ec.state;
                            return generator.non_async();
                        }
                        catch (Exception)
                        {
                            resWrap.value2 = ReplyState.ArgsTypeError;
                            return generator.non_async();
                        }
                    }
                    {
                        string field_ = ParseArray(fields[fields.Length - 1], out int[][] indices);
                        if (null == indices)
                        {
                            resWrap.value1 = null;
                            resWrap.value2 = ReplyState.Success;
                            ClassInfo method = CheckMethod(type_, null == obj_, field_, declaredOnly);
                            return method.handler(obj_, stopWg, endWg, resWrap, args);
                        }
                        bool isGet;
                        bool getLength = false;
                        if (HeadEq(field_, "set@"))
                        {
                            if (1 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            fixed (char* ptr = field_)
                            {
                                ptr[0] = 'g';
                            }
                            isGet = false;
                        }
                        else if (HeadEq(field_, "get@"))
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            isGet = true;
                        }
                        else if (HeadEq(field_, "len@"))
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            fixed (char* ptr = field_)
                            {
                                ptr[0] = 'g';
                                ptr[2] = 't';
                            }
                            isGet = true;
                            getLength = true;
                        }
                        else
                        {
                            resWrap.value2 = ReplyState.NotFound;
                            return generator.non_async();
                        }
                        resWrap.value1 = null;
                        resWrap.value2 = ReplyState.Success;
                        ClassInfo field = CheckMethod(type_, null == obj_, field_, declaredOnly);
                        if (field.arrayDim < indices.Length)
                        {
                            resWrap.value2 = ReplyState.NotFound;
                            return generator.non_async();
                        }
                        field.handler(obj_, stopWg, endWg, resWrap, EmptyArgs);
                        if (resWrap.value2 != ReplyState.Success)
                        {
                            return generator.non_async();
                        }
                        try
                        {
                            obj_ = resWrap.value1;
                            resWrap.value1 = null;
                            Array objs = (Array)obj_;
                            for (int j = 0; j < indices.Length - 1; j++)
                            {
                                objs = (Array)GetValue(objs, indices[j]);
                            }
                            if (isGet)
                            {
                                object result = GetValue(objs, indices[indices.Length - 1]);
                                if (getLength)
                                {
                                    if (field.arrayDim == indices.Length)
                                    {
                                        resWrap.value2 = ReplyState.NotFound;
                                        return generator.non_async();
                                    }
                                    Array array = (Array)result;
                                    if (null == array)
                                    {
                                        resWrap.value2 = ReplyState.IsNull;
                                        return generator.non_async();
                                    }
                                    int rank = array.Rank;
                                    if (1 == rank)
                                    {
                                        resWrap.value1 = array.GetLength(0);
                                    }
                                    else
                                    {
                                        int[] shape = new int[rank];
                                        for (int j = 0; j < rank; j++)
                                        {
                                            shape[j] = array.GetLength(j);
                                        }
                                        resWrap.value1 = shape;
                                    }
                                }
                                else
                                {
                                    resWrap.value1 = result;
                                }
                            }
                            else
                            {
                                SetValue(objs, args[0], indices[indices.Length - 1]);
                            }
                            return generator.non_async();
                        }
                        catch (IndexOutOfRangeException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (ArgumentException)
                        {
                            resWrap.value2 = ReplyState.IndexError;
                            return generator.non_async();
                        }
                        catch (CastArgsException ec)
                        {
                            resWrap.value2 = ec.state;
                            return generator.non_async();
                        }
                        catch (Exception)
                        {
                            resWrap.value2 = ReplyState.ArgsTypeError;
                            return generator.non_async();
                        }
                    }
                }, runStrand);
                _classMethods[name] = names;
                return;
            }

            static unsafe private bool HeadEq(string str, string head)
            {
                int len = head.Length;
                if (str.Length + 1 < len)
                {
                    return false;
                }
                fixed (char* ptr1 = str)
                {
                    fixed (char* ptr2 = head)
                    {
                        for (int i = 0; i < len; i++)
                        {
                            if (ptr1[i] != ptr2[i])
                            {
                                return false;
                            }
                        }
                    }
                }
                return true;
            }

            static private object GetValue(Array array, int[] indices)
            {
                if (null == array)
                {
                    throw new CastArgsException { state = ReplyState.IsNull };
                }
                for (int k = 0; k < indices.Length; k++)
                {
                    if (indices[k] < 0)
                    {
                        indices[k] = array.GetLength(k) + indices[k];
                    }
                }
                return array.GetValue(indices);
            }

            static private void SetValue(Array array, object value, int[] indices)
            {
                if (null == array)
                {
                    throw new CastArgsException { state = ReplyState.IsNull };
                }
                for (int k = 0; k < indices.Length; k++)
                {
                    if (indices[k] < 0)
                    {
                        indices[k] = array.GetLength(k) + indices[k];
                    }
                }
                array.SetValue(value, indices);
            }

            static private ClassInfo CheckMethod(Type type, bool isNull, string method, bool declaredOnly)
            {
                ClassInfo classInfo = GetMethod(type, method, declaredOnly);
                if (null == classInfo)
                {
                    throw new CastArgsException { state = ReplyState.NotFound };
                }
                if (isNull && !classInfo.isStatic)
                {
                    throw new CastArgsException { state = ReplyState.IsNull };
                }
                return classInfo;
            }

            static private ClassInfo GetMethod(Type type, string method, bool declaredOnly)
            {
                var classInfo = GetClassInfo(type);
                if (null == classInfo)
                {
                    return null;
                }
                if (classInfo.TryGetValue(method, out var value))
                {
                    return value;
                }
                if (declaredOnly)
                {
                    return null;
                }
                type = type.BaseType;
                if (null == type)
                {
                    return null;
                }
                return GetMethod(type, method, false);
            }

            static private Dictionary<string, ClassInfo> GetClassInfo(Type type)
            {
                if (_classsMap.TryGetValue(type, out var classInfo))
                {
                    return classInfo;
                }
                if (!Attribute.IsDefined(type, typeof(AllowBind), false))
                {
                    return null;
                }
                classInfo = new Dictionary<string, ClassInfo>();
                MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | InstanceFlag);
                var overrideMethod = new Dictionary<string, LinkedList<BindObjInfo>>();
                for (int i = 0; i < methods.Length; i++)
                {
                    MethodInfo method = methods[i];
                    AllowBind allowBind = (AllowBind)Attribute.GetCustomAttribute(method, typeof(AllowBind), false);
                    if (null == allowBind)
                    {
                        continue;
                    }
                    BindObjInfo methodInfo = new BindObjInfo { task = 0 };
                    methodInfo.argsType = Array.ConvertAll(method.GetParameters(), (ParameterInfo v) => v.ParameterType);
                    methodInfo.method = CreateCall(method);
                    Type returnType = method.ReturnType;
                    if (returnType.IsGenericType)
                    {
                        Type genericType = returnType.GetGenericTypeDefinition();
                        if (typeof(Task<>) == genericType)
                        {
                            methodInfo.task = 1;
                            methodInfo.getResult = CreateCall(returnType.GetMethod("get_Result"));
                        }
                        else if (typeof(ValueTask<>) == genericType)
                        {
                            methodInfo.task = 2;
                            methodInfo.valueTask = CreateCall(returnType.GetMethod("AsTask"));
                            methodInfo.getResult = CreateCall(returnType.GetMethod("get_Result"));
                        }
                    }
                    else if (typeof(Task) == returnType)
                    {
                        methodInfo.task = 3;
                    }
                    else if (typeof(ValueTask) == returnType)
                    {
                        methodInfo.task = 4;
                        methodInfo.valueTask = CreateCall(returnType.GetMethod("AsTask"));
                    }
                    string methodName = allowBind.name ?? method.Name;
                    if (!CheckName(methodName))
                    {
                        assert.check(false, $"{type.FullName} 方法命名错误 {methodName}\r\n{type.Assembly.FullName}");
                    }
                    LinkedList<BindObjInfo> sameName;
                    if (!overrideMethod.TryGetValue(methodName, out sameName))
                    {
                        sameName = new LinkedList<BindObjInfo>();
                        overrideMethod.Add(methodName, sameName);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = async (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (null != endWg && endWg.cancel)
                            {
                                return;
                            }
                            wait_group.cancel_token cancelToken = default;
                            try
                            {
                                if (null != endWg)
                                {
                                    endWg.add();
                                    if (endWg.cancel)
                                    {
                                        return;
                                    }
                                }
                                if (null != stopWg)
                                {
                                    generator self = generator.self;
                                    cancelToken = stopWg.async_wait(() => self.stop());
                                }
                                bool countError = true;
                                foreach (BindObjInfo item in sameName)
                                {
                                    if (item.argsType.Length != args.Length)
                                    {
                                        continue;
                                    }
                                    try
                                    {
                                        countError = false;
                                        object result = item.method(obj, args);
                                        switch (item.task)
                                        {
                                            case 0:
                                                {
                                                    resWrap.value1 = result;
                                                }
                                                break;
                                            case 1:
                                                {
                                                    Task task = (Task)result;
                                                    if (null != task)
                                                    {
                                                        await task;
                                                        resWrap.value1 = item.getResult(task, null);
                                                    }
                                                }
                                                break;
                                            case 2:
                                                {
                                                    Task task = (Task)item.valueTask(result, null);
                                                    if (null != task)
                                                    {
                                                        await task;
                                                    }
                                                    resWrap.value1 = item.getResult(result, null);
                                                }
                                                break;
                                            case 3:
                                                {
                                                    Task task = (Task)result;
                                                    if (null != task)
                                                    {
                                                        await task;
                                                    }
                                                }
                                                break;
                                            case 4:
                                                {
                                                    Task task = (Task)item.valueTask(result, null);
                                                    if (null != task)
                                                    {
                                                        await task;
                                                    }
                                                }
                                                break;
                                        }
                                        return;
                                    }
                                    catch (CastArgsException) { }
                                }
                                resWrap.value2 = countError ? ReplyState.ArgsCountError : ReplyState.ArgsTypeError;
                            }
                            finally
                            {
                                stopWg?.cancel_wait(cancelToken);
                                endWg?.done();
                            }
                        };
                        classInfo.Add(methodName, new ClassInfo { isStatic = method.IsStatic, handler = handler });
                    }
                    else
                    {
                        int argsCount = methodInfo.argsType.Length;
                        foreach (BindObjInfo item in sameName)
                        {
                            if (item.argsType.Length != argsCount)
                            {
                                continue;
                            }
                            bool equal = true;
                            for (int j = 0; j < argsCount; j++)
                            {
                                if (item.argsType[j] != methodInfo.argsType[j])
                                {
                                    equal = false;
                                    break;
                                }
                            }
                            if (equal)
                            {
                                assert.check(false, $"{type.FullName} 同名方法参数类型冲突 {methodName}\r\n{type.Assembly.FullName}");
                            }
                        }
                    }
                    sameName.AddLast(methodInfo);
                }
                FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | InstanceFlag);
                for (int i = 0; i < fields.Length; i++)
                {
                    FieldInfo field = fields[i];
                    AllowBind allowBind = (AllowBind)Attribute.GetCustomAttribute(field, typeof(AllowBind), false);
                    if (null == allowBind)
                    {
                        continue;
                    }
                    Type fieldType = field.FieldType;
                    int arrayDim = 0;
                    bool isArray = fieldType.IsArray;
                    bool arrayIt = isArray;
                    while (arrayIt)
                    {
                        arrayDim++;
                        fieldType = fieldType.GetElementType();
                        arrayIt = fieldType.IsArray;
                    }
                    bool isAllowBind = Attribute.IsDefined(fieldType, typeof(AllowBind), false);
                    string fieldName = allowBind.name ?? field.Name;
                    if (!CheckName(fieldName))
                    {
                        assert.check(false, $"{type.FullName} 属性命名错误 {fieldName}\r\n{type.Assembly.FullName}");
                    }
                    Func<object, object> getValue = null;
                    if (isArray)
                    {
                        getValue = CreateObjectGetter(field);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            Array array = (Array)getValue(obj);
                            if (null == array)
                            {
                                resWrap.value2 = ReplyState.IsNull;
                                return generator.non_async();
                            }
                            int rank = array.Rank;
                            if (1 == rank)
                            {
                                resWrap.value1 = array.GetLength(0);
                            }
                            else
                            {
                                int[] shape = new int[rank];
                                for (int j = 0; j < rank; j++)
                                {
                                    shape[j] = array.GetLength(j);
                                }
                                resWrap.value1 = shape;
                            }
                            return generator.non_async();
                        };
                        try
                        {
                            classInfo.Add($"len@{fieldName}", new ClassInfo { arrayDim = arrayDim, isStatic = field.IsStatic, isAllowBind = isAllowBind, fieldType = fieldType, handler = handler });
                        }
                        catch (ArgumentException)
                        {
                            assert.check(false, $"{type.FullName} 属性名称 {fieldName} 重复\r\n{type.Assembly.FullName}");
                        }
                    }
                    if (allowBind.getter)
                    {
                        getValue = getValue ?? CreateObjectGetter(field);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            resWrap.value1 = getValue(obj);
                            return generator.non_async();
                        };
                        try
                        {
                            classInfo.Add($"get@{fieldName}", new ClassInfo { arrayDim = arrayDim, isStatic = field.IsStatic, isAllowBind = isAllowBind, fieldType = fieldType, handler = handler });
                        }
                        catch (ArgumentException)
                        {
                            assert.check(false, $"{type.FullName} 属性名称 {fieldName} 重复\r\n{type.Assembly.FullName}");
                        }
                    }
                    if (allowBind.setter)
                    {
                        Action<object, object> setValue = CreateObjectSetter(field);
                        Func<object, wait_group, wait_group, async_result_wrap<object, ReplyState>, object[], Task> handler = (obj, stopWg, endWg, resWrap, args) =>
                        {
                            if (1 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            if (null != endWg && endWg.cancel)
                            {
                                return generator.non_async();
                            }
                            try
                            {
                                if (null != endWg)
                                {
                                    endWg.add();
                                    if (endWg.cancel)
                                    {
                                        return generator.non_async();
                                    }
                                }
                                setValue(obj, args[0]);
                            }
                            catch (InvalidCastException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            catch (CastArgsException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            finally
                            {
                                endWg?.done();
                            }
                            return generator.non_async();
                        };
                        try
                        {
                            classInfo.Add($"set@{fieldName}", new ClassInfo { arrayDim = arrayDim, isStatic = field.IsStatic, isAllowBind = isAllowBind, fieldType = fieldType, handler = handler });
                        }
                        catch (ArgumentException)
                        {
                            assert.check(false, $"{type.FullName} 属性名称 {fieldName} 重复\r\n{type.Assembly.FullName}");
                        }
                    }
                }
                _classsMap.TryAdd(type, classInfo);
                return classInfo;
            }

            private void Add(string name, Func<async_result_wrap<object, ReplyState>, object[], Task> handler, shared_strand runStrand)
            {
                if (!_methodsMap.TryAdd(name, tuple.make(handler, runStrand)))
                {
                    assert.check(false, $"Bind 重复的方法名 {name}");
                }
            }

            internal bool Get(string name, out tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand> handler)
            {
                return _methodsMap.TryGetValue(name, out handler);
            }

            public bool RemoveName(string name)
            {
                if (null != name && name.Length > 0)
                {
                    return _methodsMap.TryRemove(name, out var _);
                }
                return false;
            }

            public bool RemoveClass(string name)
            {
                if (null != name && name.Length > 0)
                {
                    if (_classMethods.TryRemove(name, out LinkedList<string> names))
                    {
                        foreach (var item in names)
                        {
                            RemoveName(item);
                        }
                        return true;
                    }
                }
                return false;
            }

            public bool ExistsName(string name)
            {
                return _methodsMap.ContainsKey(name);
            }

            public bool ExistsClass(string name)
            {
                return _classMethods.ContainsKey(name);
            }

            public void Clear()
            {
                _methodsMap.Clear();
                _classMethods.Clear();
            }
        }

        public class RpcException : Exception
        {
            public ReplyState code;

            public RpcException(ReplyState st)
            {
                code = st;
            }
        }

        public struct Result
        {
            public ReplyState state;
            public string message;
            public object result;

            static public implicit operator ReplyState(Result rval)
            {
                return rval.state;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }

            public R Cast<R>()
            {
                Check();
                return (R)result;
            }

            public bool Success
            {
                get
                {
                    return state == ReplyState.Success;
                }
            }
        }

        public struct Result<R>
        {
            public ReplyState state;
            public string message;
            public R result;

            static public implicit operator R(Result<R> rval)
            {
                rval.Check();
                return rval.result;
            }

            static public implicit operator ReplyState(Result<R> rval)
            {
                return rval.state;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }

            public bool Success
            {
                get
                {
                    return state == ReplyState.Success;
                }
            }
        }

        class OverSend
        {
            public bool closed;
            public int count;
            public wait_group wg;
            public LinkedList<tuple<Func<bool, Task>, RecvName>> actions;

            public OverSend()
            {
                closed = false;
                count = 0;
                wg = new wait_group(1, true);
                actions = new LinkedList<tuple<Func<bool, Task>, RecvName>>();
            }

            public RecvName[] Sends()
            {
                if (0 == count)
                {
                    return null;
                }
                RecvName[] sends = new RecvName[count];
                int num = 0;
                foreach (var item in actions)
                {
                    if (item.value2.count >= 0)
                    {
                        sends[num++] = item.value2;
                    }
                }
                return sends;
            }

            public void Close()
            {
                closed = true;
                wg.done();
            }
        }

        public struct RpcCancel
        {
            internal wait_group wg;

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void AppendNotify(Action notify)
            {
                wg.async_wait(notify);
            }

            public Task Wait()
            {
                return generator.wait_group(wg);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_group(ms, wg);
            }
        }

        public struct OverCancel
        {
            internal wait_group wg;

            static internal OverCancel Make()
            {
                return new OverCancel
                {
                    wg = new wait_group(1, true)
                };
            }

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void Cancel()
            {
                wg.force();
            }
        }

        public class CancelException : Exception
        {
            internal CancelException() { }
        }

        internal struct RecvName
        {
            public long id;
            public long count;
            public int segment;

            public bool Check()
            {
                return id > 0 && count >= 0 && segment >= 0;
            }
        }

        internal struct RecvParam
        {
            public int count;
            public long deadline;
            public long offset;
            public byte[] buff;
            public IntPtr pointer;
        }

        public class OverRecv
        {
            internal OverRecv(RecvName recvName, Session session, csp_chan<int, RecvParam> csp, OverRecv prev)
            {
                _csp = csp;
                _prev = prev;
                _session = session;
                _id = recvName.id;
                _count = recvName.count;
                _segment = recvName.segment;
                _offset = 0;
                _multiSign = 0;
                _index = -1;
                _cancel = false;
            }

            internal csp_chan<int, RecvParam> _csp;
            internal Session _session;
            internal OverRecv _prev;
            internal long _id;
            internal long _offset;
            internal long _count;
            internal int _index;
            internal int _segment;
            internal int _multiSign;
            internal bool _cancel;

            public bool Cancel => _cancel;
            public bool Big => _count > int.MaxValue;
            public bool Full => _offset == _count;
            public bool Completed => _offset == _count || _cancel;
            public long Offset => _offset;
            public long Length => _count;
            public int Segment => _segment;
            public int Index => _index;

            public Task<csp_invoke_wrap<int>> Recv(ArraySegment<byte> buff) => _session.Recv(this, buff);
            public Task<csp_invoke_wrap<int>> Recv(byte[] buff) => _session.Recv(this, buff);
            public Task<csp_invoke_wrap<int>> Recv(byte[] buff, int offset, int count) => _session.Recv(this, buff, offset, count);
            public Task<csp_invoke_wrap<int>> Recv(IntPtr pointer, long offset, int count) => _session.Recv(this, pointer, offset, count);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, ArraySegment<byte> buff) => _session.TimedRecv(this, timed, buff);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, byte[] buff) => _session.TimedRecv(this, timed, buff);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, byte[] buff, int offset, int count) => _session.TimedRecv(this, timed, buff, offset, count);
            public Task<csp_invoke_wrap<int>> TimedRecv(int timed, IntPtr pointer, long offset, int count) => _session.TimedRecv(this, timed, pointer, offset, count);
        }

        class OverSendState
        {
            public SendName name;
            public long maxCount;
            public long count;
            public ValueTask<csp_invoke_wrap<void_type>> task;
        }

        internal class SendName
        {
            static long _inc = 0;
            public long _id;
            public bool _done;

            public SendName()
            {
                _id = Interlocked.Increment(ref _inc);
            }
        }

        public class RecvDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            bool error;

            public RecvDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public RecvDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                error = false;
            }

            public void Async(Action handler)
            {
                assert.check(task.is_done, "RecvDoubleBuffer 异步任务未结束");
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] WriteData
            {
                get
                {
                    return buff1;
                }
            }

            public byte[] RecvBuff
            {
                get
                {
                    return buff2;
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class SendDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            int count;
            bool error;

            public SendDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public SendDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                count = 0;
                error = false;
            }

            public void Async(Func<int> handler)
            {
                assert.check(task.is_done, "SendDoubleBuffer 异步任务未结束");
                count = 0;
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        count = handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] ReadBuff
            {
                get
                {
                    return buff1;
                }
            }

            public ArraySegment<byte> SendData
            {
                get
                {
                    return new ArraySegment<byte>(buff2, 0, count);
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public struct RemoteMethod
        {
            internal Session session;
            internal string name;
            internal int timed;

            public bool Null => null == session;

            public RemoteMethod Timed(int timed)
            {
                this.timed = timed;
                return this;
            }

            public Task<Result> Call() => session.Call_(timed, name);
            public Task<Result> Call(object p0) => session.Call_(timed, name, p0);
            public Task<Result> Call(object p0, object p1) => session.Call_(timed, name, p0, p1);
            public Task<Result> Call(object p0, object p1, object p2) => session.Call_(timed, name, p0, p1, p2);
            public Task<Result> Call(object p0, object p1, object p2, object p3) => session.Call_(timed, name, p0, p1, p2, p3);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4) => session.Call_(timed, name, p0, p1, p2, p3, p4);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe);
            public Task<Result> Call(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => session.Call_(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf);

            public Task<Result<R>> Call<R>() => session.Call_<R>(timed, name);
            public Task<Result<R>> Call<R>(object p0) => session.Call_<R>(timed, name, p0);
            public Task<Result<R>> Call<R>(object p0, object p1) => session.Call_<R>(timed, name, p0, p1);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2) => session.Call_<R>(timed, name, p0, p1, p2);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3) => session.Call_<R>(timed, name, p0, p1, p2, p3);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe);
            public Task<Result<R>> Call<R>(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => session.Call_<R>(timed, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf);

            public Task<Result> Post() => session.Call_(0, name);
            public Task<Result> Post(object p0) => session.Call_(0, name, p0);
            public Task<Result> Post(object p0, object p1) => session.Call_(0, name, p0, p1);
            public Task<Result> Post(object p0, object p1, object p2) => session.Call_(0, name, p0, p1, p2);
            public Task<Result> Post(object p0, object p1, object p2, object p3) => session.Call_(0, name, p0, p1, p2, p3);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4) => session.Call_(0, name, p0, p1, p2, p3, p4);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5) => session.Call_(0, name, p0, p1, p2, p3, p4, p5);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe);
            public Task<Result> Post(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7, object p8, object p9, object pa, object pb, object pc, object pd, object pe, object pf) => session.Call_(0, name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe, pf);
        }

        public sealed class Session
        {
            enum DataType : byte
            {
                Keep,
                NoKeep,
                Close,
                Request,
                RequestCancel,
                Reply,
                Bin,
                BinCancel,
            }

            internal struct Request
            {
                public bool reply;
                public string name;
                public RecvName[] sends;
            }

            internal struct Reply
            {
                public ReplyState state;
                public string message;
            }

            struct SendByteParam
            {
                public SendName name;
                public int index;
                public int count;
                public long offset;
                public long deadline;
                public byte[] data;
                public IntPtr pointer;
                public SafeFileHandle file;
            }

            struct RpcParam
            {
                public long id;
                public int timed;
                public object[] args;
                public Request request;
                public OverSend overSend;
                public OverCancel overCancel;
            }

            struct RecvList
            {
                public OverRecv[] recvs;
            }

            class OverCallbackList
            {
                public wait_group stopWg;
                public wait_group endWg;
                public LinkedList<tuple<bool, string>> names;
            }

            static generator.local<Session> _callSession = new generator.local<Session>();
            static generator.local<Session> _session = new generator.local<Session>();
            static byte[] _lostBinBuff = new byte[1024 * 1024];
            static long _idCount = DateTime.Now.Ticks;

            int _keep;
            int _exitCode;
            bool _matchParamMember;
            socket _socket;
            Methods _methods;
            generator _action;
            shared_strand[] _strands;
            generator.local<OverSend> _overSend;
            generator.local<RecvList> _recvList;
            generator.local<RpcCancel> _rpcCancel;
            generator.local<OverCancel> _overCancel;
            generator.local<OverSendState> _overSendState;
            generator.local<OverCallbackList> _overCallbackList;
            csp_chan<Result, RpcParam> _rpcChan;
            csp_chan<void_type, SendName> _cancelSendChan;
            csp_chan<void_type, SendByteParam> _sendByteChan;
            chan<OverRecv> _namedRecvChan;
            chan<DataType> _remoteCmdChan;
            chan<long> _cancelRpcChan;

            public Session(shared_strand[] strands, socket socket, Methods methods, int keep = 10000, bool matchParamMember = true)
            {
                assert.check((socket is socket_tcp) || (socket is socket_pipe), "Rpc.Session 只能为 socket_tcp 或 socket_pipe");
                _keep = keep;
                _socket = socket;
                _methods = methods;
                _strands = strands;
                _matchParamMember = matchParamMember;
                _exitCode = (int)ExitCode.Undefined;
                _overSend = new generator.local<OverSend>();
                _recvList = new generator.local<RecvList>();
                _rpcCancel = new generator.local<RpcCancel>();
                _overCancel = new generator.local<OverCancel>();
                _overSendState = new generator.local<OverSendState>();
                _overCallbackList = new generator.local<OverCallbackList>();
                _rpcChan = new csp_chan<Result, RpcParam>(_strands[0]);
                _cancelSendChan = new csp_chan<void_type, SendName>(_strands[0]);
                _sendByteChan = new csp_chan<void_type, SendByteParam>(_strands[0]);
                _namedRecvChan = chan<OverRecv>.make(_strands[0], -1);
                _remoteCmdChan = chan<DataType>.make(_strands[0], -1);
                _cancelRpcChan = chan<long>.make(_strands[0], -1);
                _action = generator.make(_strands[0], () => Run(), delegate ()
                {
                    _socket.close();
                    _rpcChan.close();
                    _cancelSendChan.close();
                    _sendByteChan.close();
                    _namedRecvChan.close();
                    _remoteCmdChan.close();
                    _cancelRpcChan.close();
                });
            }

            public Session(shared_strand strand, socket socket, Methods methods, int keep = 10000, bool matchParamMember = true)
                : this(new shared_strand[] { strand }, socket, methods, keep, matchParamMember) { }

            public void Start()
            {
                _action.run();
            }

            public void Close()
            {
                SetCode(ExitCode.SessionClose);
                _action.stop();
                _strands[0].dispatch(() => _socket.close());
            }

            public void AppendNotify(Action notify)
            {
                _action.append_stop_callback(notify);
            }

            public Task Join()
            {
                return generator.wait_other(_action);
            }

            public ValueTask<bool> Join(int ms)
            {
                return generator.timed_wait_other(ms, _action);
            }

            public bool Closed
            {
                get
                {
                    return _action.is_completed();
                }
            }

            public ExitCode Code
            {
                get
                {
                    return (ExitCode)_exitCode;
                }
            }

            public Methods Methods
            {
                get
                {
                    return _methods;
                }
            }

            public RemoteMethod this[string name]
            {
                get
                {
                    return new RemoteMethod { session = this, name = name, timed = -1 };
                }
            }

            public RemoteMethod this[string name1, string name2]
            {
                get
                {
                    return this[Methods.Name.Concat(name1, name2)];
                }
            }

            public RemoteMethod this[string name1, string name2, string name3]
            {
                get
                {
                    return this[Methods.Name.Concat(name1, name2, name3)];
                }
            }

            public RemoteMethod this[string name1, string name2, string name3, string name4]
            {
                get
                {
                    return this[Methods.Name.Concat(name1, name2, name3, name4)];
                }
            }

            public RemoteMethod this[string name, int timed]
            {
                get
                {
                    return new RemoteMethod { session = this, name = name, timed = timed };
                }
            }

            public RemoteMethod this[string name1, string name2, int timed]
            {
                get
                {
                    return this[Methods.Name.Concat(name1, name2), timed];
                }
            }

            public RemoteMethod this[string name1, string name2, string name3, int timed]
            {
                get
                {
                    return this[Methods.Name.Concat(name1, name2, name3), timed];
                }
            }

            public RemoteMethod this[string name1, string name2, string name3, string name4, int timed]
            {
                get
                {
                    return this[Methods.Name.Concat(name1, name2, name3, name4), timed];
                }
            }

            static private void Swap<T>(ref T a, ref T b)
            {
                T t = a;
                a = b;
                b = t;
            }

            static private unsafe void ReadHead(byte[] recvHead, out long id, out int len1, out int len2, out DataType type)
            {
                fixed (byte* ptr = recvHead)
                {
                    id = *(long*)ptr;
                    len1 = *(int*)(ptr + 8);
                    len2 = *(int*)(ptr + 12);
                    type = (DataType)(byte)*(ptr + 16);
                }
            }

            static private unsafe void WriteHead(byte[] sendHead, long id, int len1, int len2, DataType type)
            {
                fixed (byte* ptr = sendHead)
                {
                    *(long*)ptr = id;
                    *(int*)(ptr + 8) = len1;
                    *(int*)(ptr + 12) = len2;
                    *(ptr + 16) = (byte)type;
                }
            }

            static public Session Self
            {
                get
                {
                    _session.deep_get(out Session self);
                    return self;
                }
            }

            static public RpcCancel CancelWait()
            {
                Session self = Self;
                assert.check(null != self, "不在 Rpc.Session 上下文中");
                self._rpcCancel.deep_get(out RpcCancel value);
                return value;
            }

            static public OverRecv[] OverRecv()
            {
                Session self = Self;
                assert.check(null != self, "不在 Rpc.Session 上下文中");
                if (!self._recvList.deep_get(out RecvList value))
                {
                    return null;
                }
                return value.recvs;
            }

            static public void ThrowCancel()
            {
                _session.get(out Session self);
                assert.check(null != self, "不在 Rpc.Session 根上下文中");
                throw new CancelException();
            }

            public async Task DiscardRecv(OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                for (int i = 0; i < recvs.Length; i++)
                {
                    while (!recvs[i].Completed)
                    {
                        csp_invoke_wrap<int> recvRes = await recvs[i].TimedRecv(_keep, _lostBinBuff, 0, _lostBinBuff.Length);
                        if (recvRes.state != chan_state.ok)
                        {
                            SetCode(ExitCode.RecvBinOvertime);
                            _action.stop();
                            return;
                        }
                        await generator.try_yield();
                    }
                }
            }

            public async Task DiscardChaoticRecv(params OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                generator.lock_shield();
                generator.children children = new generator.children();
                children.ignore_suspend();
                for (int i = 0; i < recvs.Length; i++)
                {
                    int j = i;
                    children.go(async delegate ()
                    {
                        while (!recvs[j].Completed)
                        {
                            await Recv(recvs[j], _lostBinBuff, 0, _lostBinBuff.Length);
                            await generator.try_yield();
                        }
                    });
                }
                await children.wait_all();
                await generator.unlock_shield();
            }

            public OverCancel OverCancel()
            {
                assert.check(!_overCancel.get(out _), "重复的 OverCancel");
                OverCancel call = Rpc.OverCancel.Make();
                _overCancel.value = call;
                return call;
            }

            public void ClearOverSend()
            {
                _overSend.remove(out _);
            }

            private int OverSend(Func<bool, Task> action, SendName name, long count, int segment)
            {
                if (!_overSend.get(out OverSend send))
                {
                    send = new OverSend();
                    _overSend.value = send;
                }
                if (count >= 0 && send.count >= ushort.MaxValue)
                {
                    assert.check(false, "OverSend最多65535个");
                }
                send.actions.AddLast(tuple.make(action, new RecvName { id = name._id, count = count, segment = segment }));
                return count >= 0 ? send.count++ : -1;
            }

            private int OverSend(Func<bool, ValueTask<csp_invoke_wrap<void_type>>> action, SendName name, long count, int segment)
            {
                return OverSend((bool cancel) => action(cancel).AsTask() ?? generator.non_async(), name, count, segment);
            }

            private ValueTask<csp_invoke_wrap<void_type>> CancelSend(SendName name)
            {
                return generator.csp_invoke(_cancelSendChan, name);
            }

            private OverSendState CheckOverSendState(int count)
            {
                if (_overSendState.get(out OverSendState sendState))
                {
                    if (!sendState.task.IsCompleted)
                    {
                        assert.check(false, "OverSend 发送异步结果未结束");
                    }
                    if (count > sendState.maxCount)
                    {
                        assert.check(false, "OverSend 发送长度溢出");
                    }
                    sendState.count += count;
                    sendState.maxCount -= count;
                }
                else
                {
                    assert.check(false, "错误的 Send");
                }
                return sendState;
            }

            public int OverSend(long count, Func<long, long, ValueTask<csp_invoke_wrap<void_type>>> sendAction)
            {
                return OverSend(count, (long offset_, long count_) => sendAction(offset_, count_).AsTask() ?? generator.non_async());
            }

            public int OverSend(long count, Func<long, long, Task> sendAction)
            {
                SendName name = new SendName { _done = count <= 0 };
                return OverSend(async delegate (bool cancel)
                {
                    if (cancel)
                    {
                        await CancelSend(name);
                        return;
                    }
                    try
                    {
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        for (long off = 0; off < count;)
                        {
                            if (0 != off)
                            {
                                await generator.try_yield();
                                generator.lock_stop();
                            }
                            sendState.count = 0;
                            sendState.maxCount = count - off;
                            await sendAction(off, count - off);
                            if (!sendState.task.IsCompleted)
                            {
                                assert.check(false, "OverSend 发送异步结果未结束");
                            }
                            chan_state state = sendState.task.Result;
                            long len = sendState.count;
                            if (len <= 0)
                            {
                                await CancelSend(name);
                                return;
                            }
                            if (state != chan_state.ok)
                            {
                                await CancelSend(name);
                                return;
                            }
                            off += len;
                            if (count != off)
                            {
                                generator.unlock_stop();
                            }
                        }
                        name._done = true;
                    }
                    catch (generator.stop_exception)
                    {
                        await CancelSend(name);
                        throw;
                    }
                }, name, count, 0);
            }

            public int OverSend(ArraySegment<byte> data, int segment = 0, int interval = 0)
            {
                return OverTimedSend(-1, data, segment, interval);
            }

            public int OverSend(byte[] data, int segment = 0, int interval = 0)
            {
                return OverTimedSend(-1, data, 0, data.Length, segment, interval);
            }

            public int OverSend(byte[] data, int offset, int count, int segment = 0, int interval = 0)
            {
                return OverTimedSend(-1, data, offset, count, segment, interval);
            }

            public int OverSend(IntPtr pointer, long offset, long count, int segment = 0, int interval = 0)
            {
                return OverTimedSend(-1, pointer, offset, count, segment, interval);
            }

            public int OverSend(SafeFileHandle file, long offset, long count, int segment = 0, int interval = 0)
            {
                return OverTimedSend(-1, file, offset, count, segment, interval);
            }

            public int OverTimedSend(int timed, ArraySegment<byte> data, int segment = 0, int interval = 0)
            {
                return OverTimedSend(timed, data.Array, data.Offset, data.Count, segment, interval);
            }

            public int OverTimedSend(int timed, byte[] data, int offset, int count, int segment = 0, int interval = 0)
            {
                assert.check(null != data, "TimedSend data 不能为 null");
                assert.check(offset >= 0 && offset < data.Length, "TimedSend offset 越界");
                assert.check(count <= 0 || offset + count <= data.Length, "TimedSend count 越界");
                SendName name = new SendName { _done = count <= 0 };
                if (segment > 0 && segment < count)
                {
                    return OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        async_timer sendTimer = null;
                        chan<void_type> sendChan = null;
                        try
                        {
                            if (0 != interval)
                            {
                                sendTimer = new async_timer();
                                sendChan = chan<void_type>.make(1);
                                sendTimer.interval(Math.Abs(interval), sendChan.wrap_try_default(), interval < 0);
                            }
                            segment = segment <= 0 ? count : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (int off = 0; off < count; index++)
                            {
                                int len = Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    if (0 != interval)
                                    {
                                        await sendChan.receive();
                                    }
                                    else
                                    {
                                        await generator.try_yield();
                                    }
                                    generator.lock_stop();
                                }
                                else if (0 != interval)
                                {
                                    generator.unlock_stop();
                                    await sendChan.receive();
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend_(timed, data, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                        finally
                        {
                            sendTimer?.cancel();
                        }
                    }, name, count, segment);
                }
                else
                {
                    return OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend_(timed, data, offset, count, -1);
                    }, name, count, 0);
                }
            }

            public int OverTimedSend(int timed, IntPtr pointer, long offset, long count, int segment = 0, int interval = 0)
            {
                assert.check(IntPtr.Zero != pointer, "OverTimedSend pointer 不能为 Zero");
                SendName name = new SendName { _done = count <= 0 };
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    return OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        async_timer sendTimer = null;
                        chan<void_type> sendChan = null;
                        try
                        {
                            if (0 != interval)
                            {
                                sendTimer = new async_timer();
                                sendChan = chan<void_type>.make(1);
                                sendTimer.interval(Math.Abs(interval), sendChan.wrap_try_default(), interval < 0);
                            }
                            segment = segment <= 0 ? (int)Math.Min(int.MaxValue, count) : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (long off = 0; off < count; index++)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    if (0 != interval)
                                    {
                                        await sendChan.receive();
                                    }
                                    else
                                    {
                                        await generator.try_yield();
                                    }
                                    generator.lock_stop();
                                }
                                else if (0 != interval)
                                {
                                    generator.unlock_stop();
                                    await sendChan.receive();
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend_(timed, pointer, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                        finally
                        {
                            sendTimer?.cancel();
                        }
                    }, name, count, segment);
                }
                else
                {
                    return OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend_(timed, pointer, offset, (int)count, -1);
                    }, name, count, 0);
                }
            }

            public int OverTimedSend(int timed, SafeFileHandle file, long offset, long count, int segment = 0, int interval = 0)
            {
                assert.check(_socket is socket_tcp, "TimedSend 文件发送只能为 socket_tcp");
                SendName name = new SendName { _done = count <= 0 };
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    return OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        async_timer sendTimer = null;
                        chan<void_type> sendChan = null;
                        try
                        {
                            if (0 != interval)
                            {
                                sendTimer = new async_timer();
                                sendChan = chan<void_type>.make(1);
                                sendTimer.interval(Math.Abs(interval), sendChan.wrap_try_default(), interval < 0);
                            }
                            segment = segment <= 0 ? (int)Math.Min(int.MaxValue, count) : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (long off = 0; off < count; index++)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    if (0 != interval)
                                    {
                                        await sendChan.receive();
                                    }
                                    else
                                    {
                                        await generator.try_yield();
                                    }
                                    generator.lock_stop();
                                }
                                else if (0 != interval)
                                {
                                    generator.unlock_stop();
                                    await sendChan.receive();
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend_(timed, file, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                        finally
                        {
                            sendTimer?.cancel();
                        }
                    }, name, count, segment);
                }
                else
                {
                    return OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend_(timed, file, offset, (int)count, -1);
                    }, name, count, 0);
                }
            }

            public void OverHandler(Action handler)
            {
                SendName name = new SendName { _done = true };
                OverSend(delegate (bool cancel)
                {
                    if (!cancel)
                    {
                        handler();
                    }
                    return generator.non_async();
                }, name, -1, 0);
            }

            public void OverHandler(Func<Task> handler)
            {
                SendName name = new SendName { _done = true };
                OverSend(delegate (bool cancel)
                {
                    if (cancel)
                    {
                        return generator.non_async();
                    }
                    return handler();
                }, name, -1, 0);
            }

            public void CancelOverSend()
            {
                _overSend.remove();
            }

            OverCallbackList GetCallbackList(bool overStopCallback, bool waitCallbackEnd)
            {
                if (!_overCallbackList.get(out OverCallbackList callbackList))
                {
                    callbackList = new OverCallbackList();
                    callbackList.names = new LinkedList<tuple<bool, string>>();
                    _overCallbackList.value = callbackList;
                }
                if (overStopCallback && null == callbackList.stopWg)
                {
                    callbackList.stopWg = new wait_group(1, true);
                }
                if (waitCallbackEnd && null == callbackList.endWg)
                {
                    callbackList.endWg = new wait_group();
                }
                return callbackList;
            }

            public Task ClearCallback()
            {
                if (_overCallbackList.get(out OverCallbackList callbackList))
                {
                    while (0 != callbackList.names.Count)
                    {
                        tuple<bool, string> value = callbackList.names.First.Value;
                        callbackList.names.RemoveFirst();
                        if (value.value1)
                        {
                            Methods.RemoveName(value.value2);
                        }
                        else
                        {
                            Methods.RemoveClass(value.value2);
                        }
                    }
                    if (null != callbackList.stopWg)
                    {
                        callbackList.stopWg.force();
                        callbackList.stopWg = null;
                    }
                    if (null != callbackList.endWg)
                    {
                        wait_group endWg = callbackList.endWg;
                        callbackList.endWg = null;
                        return endWg.wait();
                    }
                }
                return generator.non_async();
            }

            public Methods.Name OverCallback(Action callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0>(Action<T0> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1>(Action<T0, T1> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2>(Action<T0, T1, T2> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3>(Action<T0, T1, T2, T3> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4>(Action<T0, T1, T2, T3, T4> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5>(Action<T0, T1, T2, T3, T4, T5> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6>(Action<T0, T1, T2, T3, T4, T5, T6> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7>(Action<T0, T1, T2, T3, T4, T5, T6, T7> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);

            public Methods.Name OverCallback<R>(Func<R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, R>(Func<T0, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, R>(Func<T0, T1, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, R>(Func<T0, T1, T2, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, R>(Func<T0, T1, T2, T3, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, R>(Func<T0, T1, T2, T3, T4, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, R>(Func<T0, T1, T2, T3, T4, T5, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, R>(Func<T0, T1, T2, T3, T4, T5, T6, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);
            public Methods.Name OverCallback<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null) => OverCallback((Delegate)callback, overStopCallback, waitCallbackEnd, runStrand);

            public Methods.Name OverCallback(Delegate callback, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                OverCallbackList callbackList = GetCallbackList(overStopCallback, waitCallbackEnd);
                wait_group stopWg = overStopCallback ? callbackList.stopWg : null;
                wait_group endWg = waitCallbackEnd ? callbackList.endWg : null;
                Methods.Bind(name, callback, stopWg, endWg, runStrand ?? generator.self_strand());
                callbackList.names.AddLast(tuple.make(true, name.name));
                return name;
            }

            public Methods.Name OverStatic(Type type, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                OverCallbackList callbackList = GetCallbackList(overStopCallback, waitCallbackEnd);
                wait_group stopWg = overStopCallback ? callbackList.stopWg : null;
                wait_group endWg = waitCallbackEnd ? callbackList.endWg : null;
                Methods.BindClass(name, type, null, false, stopWg, endWg, runStrand ?? generator.self_strand());
                callbackList.names.AddLast(tuple.make(false, name.name));
                return name;
            }

            public Methods.Name OverStatic<T>(bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                return OverStatic(typeof(T), overStopCallback, waitCallbackEnd, runStrand);
            }

            public Methods.Name OverObj<T>(T obj, bool declaredOnly = true, bool overStopCallback = false, bool waitCallbackEnd = false, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                OverCallbackList callbackList = GetCallbackList(overStopCallback, waitCallbackEnd);
                wait_group stopWg = overStopCallback ? callbackList.stopWg : null;
                wait_group endWg = waitCallbackEnd ? callbackList.endWg : null;
                Methods.BindClass(name, typeof(T), obj, declaredOnly, stopWg, endWg, runStrand ?? generator.self_strand());
                callbackList.names.AddLast(tuple.make(false, name.name));
                return name;
            }

            internal async Task<Result> Call_(int timed, string name, params object[] args)
            {
                long requestId = 0;
                generator sendAction = null;
                _overSend.remove(out OverSend overSend);
                _overCancel.remove(out OverCancel overCancel);
                try
                {
                    if (_rpcChan.closed)
                    {
                        return new Result { state = ReplyState.Fail };
                    }
                    if (!overCancel.Nil && overCancel.wg.is_done)
                    {
                        return new Result { state = ReplyState.LocalCancel };
                    }
                    if (null != overSend && overSend.actions.Count > 0)
                    {
                        generator.go(out sendAction, generator.self_strand(), async delegate ()
                        {
                            try
                            {
                                _callSession.value = this;
                                generator.lock_stop();
                                await overSend.wg.wait();
                                if (overSend.closed)
                                {
                                    overSend.actions.Clear();
                                }
                                generator.unlock_stop();
                                _overSendState.value = new OverSendState();
                                while (overSend.actions.Count > 0)
                                {
                                    generator.lock_stop();
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(false);
                                    generator.unlock_stop();
                                    await generator.try_yield();
                                }
                            }
                            catch (generator.stop_exception)
                            {
                                while (overSend.actions.Count > 0)
                                {
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(true);
                                }
                                throw;
                            }
                            finally
                            {
                                _overSendState.remove();
                            }
                        });
                    }
                    requestId = Interlocked.Increment(ref _idCount);
                    csp_invoke_wrap<Result> resultWrap = await generator.csp_invoke(_rpcChan, new RpcParam { id = requestId, timed = timed, args = args, overSend = overSend, overCancel = overCancel, request = new Request { name = name, sends = overSend?.Sends() } });
                    if (chan_state.ok != resultWrap.state)
                    {
                        if (chan_state.closed == resultWrap.state)
                        {
                            requestId = 0;
                            overSend?.Close();
                        }
                        return new Result { state = ReplyState.Fail };
                    }
                    switch (resultWrap.result.state)
                    {
                        case ReplyState.Overtime:
                        case ReplyState.LocalCancel:
                            return resultWrap.result;
                        default:
                            if (null != sendAction && !sendAction.is_completed() && 0 == timed && ReplyState.Success == resultWrap.result.state)
                            {
                                overCancel.wg?.async_wait(() => sendAction.stop());
                                await generator.wait_other(sendAction);
                                if (sendAction.is_force())
                                {
                                    resultWrap.result.state = ReplyState.LocalCancel;
                                }
                            }
                            requestId = 0;
                            return resultWrap.result;
                    }
                }
                catch (generator.stop_exception)
                {
                    if (null != sendAction)
                    {
                        if (_rpcChan.closed)
                        {
                            requestId = 0;
                            overSend.Close();
                        }
                        else if (!_rpcChan.strand.running_in_this_thread())
                        {
                            _rpcChan.strand.post(delegate ()
                            {
                                if (_rpcChan.closed)
                                {
                                    overSend.Close();
                                }
                            });
                        }
                    }
                    throw;
                }
                finally
                {
                    generator.lock_shield();
                    if (null != sendAction && !sendAction.is_completed())
                    {
                        await generator.stop_other(sendAction);
                    }
                    if (0 != requestId)
                    {
                        _cancelRpcChan.post(requestId);
                    }
                    await ClearCallback();
                    await generator.unlock_shield();
                }
            }

            internal async Task<Result<R>> Call_<R>(int timed, string name, params object[] args)
            {
                Result result = await Call_(timed, name, args);
                if (result.state != ReplyState.Success)
                {
                    return new Result<R> { state = result.state, message = result.message };
                }
                try
                {
                    return new Result<R> { state = result.state, result = (R)result.result };
                }
                catch (Exception)
                {
                    return new Result<R> { state = ReplyState.ResultTypeError };
                }
            }

            public void RemoteClose()
            {
                _remoteCmdChan.post(DataType.Close);
            }

            public void NoKeep()
            {
                _remoteCmdChan.post(DataType.NoKeep);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(ArraySegment<byte> data, int index = -1)
            {
                return TimedSend(-1, data.Array, data.Offset, data.Count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(byte[] data, int index = -1)
            {
                return TimedSend(-1, data, 0, data.Length, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(byte[] data, int offset, int count, int index = -1)
            {
                return TimedSend(-1, data, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(IntPtr pointer, long offset, int count, int index = -1)
            {
                return TimedSend(-1, pointer, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> Send(SafeFileHandle file, long offset, int count, int index = -1)
            {
                return TimedSend(-1, file, offset, count, index);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, ArraySegment<byte> buff)
            {
                return TimedRecv(name, -1, buff.Array, buff.Offset, buff.Count);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, byte[] buff)
            {
                return TimedRecv(name, -1, buff, 0, buff.Length);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, byte[] buff, int offset, int count)
            {
                return TimedRecv(name, -1, buff, offset, count);
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, IntPtr pointer, long offset, int count)
            {
                return TimedRecv(name, -1, pointer, offset, count);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, ArraySegment<byte> data, int index = -1)
            {
                return TimedSend(timed, data.Array, data.Offset, data.Count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, byte[] data, int index = -1)
            {
                return TimedSend(timed, data, 0, data.Length, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, byte[] data, int offset, int count, int index = -1)
            {
                if (!_callSession.get(out Session this_))
                {
                    assert.check(false, "错误的 Send");
                }
                return this_.TimedSend_(timed, data, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, IntPtr pointer, long offset, int count, int index = -1)
            {
                if (!_callSession.get(out Session this_))
                {
                    assert.check(false, "错误的 Send");
                }
                return this_.TimedSend_(timed, pointer, offset, count, index);
            }

            static public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, SafeFileHandle file, long offset, int count, int index = -1)
            {
                if (!_callSession.get(out Session this_))
                {
                    assert.check(false, "错误的 Send");
                }
                return this_.TimedSend_(timed, file, offset, count, index);
            }

            private ValueTask<csp_invoke_wrap<void_type>> TimedSend_(int timed, byte[] data, int offset, int count, int index)
            {
                assert.check(null != data, "TimedSend data 不能为 null");
                assert.check(offset >= 0 && offset < data.Length, "TimedSend offset 越界");
                assert.check(count > 0 && offset + count <= data.Length, "TimedSend count 越界");
                OverSendState sendState = CheckOverSendState(count);
                long deadline = timed > 0 ? system_tick.ms + timed : 0;
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { name = sendState.name, deadline = deadline, index = index, data = data, offset = offset, count = count });
            }

            private ValueTask<csp_invoke_wrap<void_type>> TimedSend_(int timed, IntPtr pointer, long offset, int count, int index)
            {
                assert.check(IntPtr.Zero != pointer, "TimedSend pointer 不能为 Zero");
                OverSendState sendState = CheckOverSendState(count);
                long deadline = timed > 0 ? system_tick.ms + timed : 0;
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { name = sendState.name, deadline = deadline, index = index, pointer = pointer, offset = offset, count = count });
            }

            private ValueTask<csp_invoke_wrap<void_type>> TimedSend_(int timed, SafeFileHandle file, long offset, int count, int index)
            {
                assert.check(_socket is socket_tcp, "TimedSend 文件发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                long deadline = timed > 0 ? system_tick.ms + timed : 0;
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { name = sendState.name, deadline = deadline, index = index, file = file, offset = offset, count = count });
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, ArraySegment<byte> buff)
            {
                return TimedRecv(name, timed, buff.Array, buff.Offset, buff.Count);
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, byte[] buff)
            {
                return TimedRecv(name, timed, buff, 0, buff.Length);
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, byte[] buff, int offset, int count)
            {
                assert.check(name._session == this, "OverRecv 不属于当前 Session");
                assert.check(null == name._prev || name._prev.Completed, "OverRecv 接收顺序错误");
                assert.check(null != buff, "TimedRecv buff 不能为 null");
                assert.check(offset >= 0 && offset < buff.Length, "TimedRecv offset 越界");
                assert.check(count > 0 && offset + count <= buff.Length, "TimedRecv count 越界");
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    assert.check(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (name.Full)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                chan_state state = await generator.chan_send(_namedRecvChan, name);
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                long deadline = timed > 0 ? system_tick.ms + timed : 0;
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(name._csp, timed, new RecvParam { deadline = deadline, buff = buff, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, IntPtr pointer, long offset, int count)
            {
                assert.check(name._session == this, "OverRecv 不属于当前 Session");
                assert.check(null == name._prev || name._prev.Completed, "OverRecv 接收顺序错误");
                assert.check(IntPtr.Zero != pointer, "TimedRecv pointer 不能为 Zero");
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    assert.check(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (name.Full)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    name._multiSign = 0;
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                chan_state state = await generator.chan_send(_namedRecvChan, name);
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                long deadline = timed > 0 ? system_tick.ms + timed : 0;
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(name._csp, timed, new RecvParam { deadline = deadline, pointer = pointer, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            struct ReplyMapValue
            {
                public async_timer timer;
                public csp_result<Result> result;
            }

            struct SendRequestParam
            {
                public long id;
                public object[] args;
                public Request request;
                public OverSend overSend;
            }

            struct RecvRequestParam
            {
                public long id;
                public bool cancel;
                public object[] args;
                public string[] fields;
                public Request request;
            }

            struct RecvReplyParam
            {
                public long id;
                public ReplyState state;
                public object result;
                public Reply reply;
            }

            struct SendReplyParam
            {
                public long id;
                public object result;
                public Reply reply;
            }

            struct SendBuffParam
            {
                public int count;
                public OverSend overSend;
            }

            private void SetCode(ExitCode code)
            {
                Interlocked.CompareExchange(ref _exitCode, (int)code, (int)ExitCode.Undefined);
            }

            private async Task Run()
            {
                generator.children ioChild = new generator.children();
                chan_lost_msg<csp_wait_wrap<Result, RpcParam>> rpcLost = new chan_lost_msg<csp_wait_wrap<Result, RpcParam>>();
                Dictionary<long, ReplyMapValue> replyDict = new Dictionary<long, ReplyMapValue>();
                chan<SendRequestParam> sendRequestChan = chan<SendRequestParam>.make(-1);
                try
                {
                    if (_keep <= 0)
                    {
                        NoKeep();
                    }
                    bool isTcp = _socket is socket_tcp;
                    bool sendBin = false, recvBin = false;
                    const int buffSize = 1024 * 1024;
                    async_timer recvTimer = new async_timer();
                    async_timer sendTimer = new async_timer();
                    chan<RecvRequestParam> recvRequestChan = chan<RecvRequestParam>.make(-1);
                    chan<RecvReplyParam> recvReplyChan = chan<RecvReplyParam>.make(-1);
                    chan<SendReplyParam> sendReplyChan = chan<SendReplyParam>.make(-1);
                    ioChild.go(async delegate ()
                    {
                        byte[] recvHead = new byte[17];
                        Serializer deserializer1 = new Serializer(new byte[buffSize], 0, buffSize, _matchParamMember);
                        Serializer deserializer2 = new Serializer(new byte[buffSize], 0, buffSize, _matchParamMember);
                        Map<long, OverRecv> namedMap = new Map<long, OverRecv>(true);
                        chan_lost_msg<OverRecv> namedLost = new chan_lost_msg<OverRecv>();
                        try
                        {
                            DataType lastType = DataType.Keep;
                            Action timerKeepHandler = delegate ()
                            {
                                switch (lastType)
                                {
                                    case DataType.Bin:
                                    case DataType.BinCancel:
                                        SetCode(ExitCode.RecvKeepOvertime);
                                        break;
                                    default:
                                        SetCode(ExitCode.KeepOvertime);
                                        break;
                                }
                                _action.stop();
                            };
                            Action timerRecvHandler = delegate ()
                            {
                                SetCode(ExitCode.RecvBinOvertime);
                                _action.stop();
                            };
                            if (_keep > 0)
                            {
                                recvTimer.timeout(_keep, timerKeepHandler);
                            }
                            Task deserializeTask = generator.non_async();
                            while (true)
                            {
                                if (!await _socket.read(recvHead))
                                {
                                    goto socketClosed;
                                }
                                recvTimer.restart();
                                ReadHead(recvHead, out long id, out int len1, out int len2, out DataType type);
                                lastType = type;
                                switch (type)
                                {
                                    case DataType.Keep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        break;
                                    case DataType.NoKeep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        _keep = -1;
                                        recvTimer.cancel();
                                        if (!sendBin)
                                        {
                                            sendTimer.cancel();
                                        }
                                        break;
                                    case DataType.RequestCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        recvRequestChan.post(new RecvRequestParam { id = id, cancel = true });
                                        break;
                                    case DataType.Request:
                                    case DataType.Reply:
                                        if (len1 <= 0 || len2 < 0 || len1 + len2 > buffSize)
                                        {
                                            goto dataHeadError;
                                        }
                                        if (!await _socket.read(new ArraySegment<byte>(deserializer1.Buffer, 0, len1 + len2)))
                                        {
                                            goto socketClosed;
                                        }
                                        await generator.wait_task(deserializeTask);
                                        Swap(ref deserializer1, ref deserializer2);
                                        (deserializeTask = new Task(delegate ()
                                        {
                                            switch (type)
                                            {
                                                case DataType.Request:
                                                    try
                                                    {
                                                        deserializer2.Position = 0;
                                                        Request request = deserializer2.DeserializeRequest();
                                                        if (deserializer2.Position != len1)
                                                        {
                                                            SetCode(ExitCode.RequestDeserializeError);
                                                            _action.stop();
                                                            break;
                                                        }
                                                        try
                                                        {
                                                            string[] fields = null;
                                                            if (request.name[request.name.Length - 1] == ']')
                                                            {
                                                                fields = request.name.Split('.');
                                                                request.name = fields[0];
                                                            }
                                                            else
                                                            {
                                                                bool lastDot = false;
                                                                for (int i = 0; i < request.name.Length; i++)
                                                                {
                                                                    if (request.name[i] != '.')
                                                                    {
                                                                        continue;
                                                                    }
                                                                    if (lastDot)
                                                                    {
                                                                        fields = request.name.Split('.');
                                                                        request.name = fields[0];
                                                                        break;
                                                                    }
                                                                    lastDot = true;
                                                                }
                                                            }
                                                            object[] args;
                                                            if (0 != len2)
                                                            {
                                                                args = (object[])deserializer2.Deserialize();
                                                                if (deserializer2.Position != len1 + len2)
                                                                {
                                                                    sendReplyChan.post(new SendReplyParam { id = id, reply = new Reply { state = ReplyState.RemoteDeserializeError } });
                                                                    break;
                                                                }
                                                            }
                                                            else
                                                            {
                                                                args = EmptyArgs;
                                                            }
                                                            recvRequestChan.post(new RecvRequestParam { id = id, cancel = false, args = args, fields = fields, request = request });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            sendReplyChan.post(new SendReplyParam { id = id, reply = new Reply { state = ReplyState.RemoteDeserializeError } });
                                                            if (null != request.sends)
                                                            {
                                                                recvRequestChan.post(new RecvRequestParam { id = id, cancel = true, request = request });
                                                            }
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        SetCode(ExitCode.RequestDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                                case DataType.Reply:
                                                    try
                                                    {
                                                        deserializer2.Position = 0;
                                                        Reply reply = deserializer2.DeserializeReply();
                                                        if (deserializer2.Position != len1)
                                                        {
                                                            SetCode(ExitCode.ReplyDeserializeError);
                                                            _action.stop();
                                                            break;
                                                        }
                                                        try
                                                        {
                                                            object result = null;
                                                            if (0 != len2 && reply.state == ReplyState.Success)
                                                            {
                                                                result = deserializer2.Deserialize();
                                                                if (deserializer2.Position != len1 + len2)
                                                                {
                                                                    sendReplyChan.post(new SendReplyParam { id = id, reply = new Reply { state = ReplyState.LocalDeserializeError } });
                                                                    break;
                                                                }
                                                            }
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, result = result, reply = reply });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalDeserializeError } });
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        SetCode(ExitCode.ReplyDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                            }
                                        })).Start();
                                        break;
                                    case DataType.Bin:
                                        if (len2 <= 0)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            int position = 0;
                                            bool lastFind = true;
                                            while (position != len2)
                                            {
                                                var tempNode = lastFind ? namedMap.FindFirst(id) : null;
                                                if (!(lastFind = null != tempNode))
                                                {
                                                    do
                                                    {
                                                        chan_recv_wrap<OverRecv> namedCsp = await _namedRecvChan.receive(namedLost);
                                                        tempNode = namedMap.Insert(namedCsp.msg._id, namedCsp.msg);
                                                    } while (tempNode.Key != id);
                                                }
                                                tempNode.Value._index = len1;
                                                csp_wait_wrap<int, RecvParam> cspParam = await tempNode.Value._csp.wait();
                                                if (cspParam.state != chan_state.ok)
                                                {
                                                    goto socketClosed;
                                                }
                                                int count = cspParam.msg.count;
                                                if (count > len2 - position)
                                                {
                                                    count = len2 - position;
                                                }
                                                if (count <= 0)
                                                {
                                                    recvTimer.restart();
                                                    cspParam.complete(0);
                                                }
                                                else
                                                {
                                                    recvBin = true;
                                                    recvTimer.cancel();
                                                    if (cspParam.msg.deadline > 0)
                                                    {
                                                        recvTimer.deadline(cspParam.msg.deadline, timerRecvHandler);
                                                    }
                                                    socket_result result;
                                                    generator.lock_stop();
                                                    if (IntPtr.Zero == cspParam.msg.pointer)
                                                    {
                                                        result = await _socket.read(new ArraySegment<byte>(cspParam.msg.buff, (int)cspParam.msg.offset, count));
                                                    }
                                                    else if (isTcp)
                                                    {
                                                        result = await ((socket_tcp)_socket).read(cspParam.msg.pointer, cspParam.msg.offset, count);
                                                    }
                                                    else
                                                    {
                                                        result = await ((socket_pipe)_socket).read(cspParam.msg.pointer, cspParam.msg.offset, count);
                                                    }
                                                    generator.unlock_stop();
                                                    if (!result)
                                                    {
                                                        cspParam.complete(-1);
                                                        goto socketClosed;
                                                    }
                                                    position += result.size;
                                                    recvBin = false;
                                                    if (cspParam.msg.deadline > 0)
                                                    {
                                                        recvTimer.cancel();
                                                    }
                                                    if (_keep > 0)
                                                    {
                                                        recvTimer.timeout(_keep, timerKeepHandler);
                                                    }
                                                    cspParam.complete(result.size);
                                                }
                                                namedMap.Remove(tempNode);
                                            }
                                        }
                                        break;
                                    case DataType.BinCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            var tempNode = namedMap.FindFirst(id);
                                            if (null == tempNode)
                                            {
                                                do
                                                {
                                                    chan_recv_wrap<OverRecv> namedCsp = await _namedRecvChan.receive(namedLost);
                                                    tempNode = namedMap.Insert(namedCsp.msg._id, namedCsp.msg);
                                                } while (tempNode.Key != id);
                                            }
                                            (await tempNode.Value._csp.wait()).complete(-2);
                                            namedMap.Remove(tempNode);
                                        }
                                        break;
                                    case DataType.Close:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        SetCode(ExitCode.RemoteClose);
                                        return;
                                    default:
                                        goto dataHeadError;
                                }
                            }
dataHeadError:
                            SetCode(ExitCode.DataHeadError);
                            return;
socketClosed:
                            SetCode(ExitCode.SocketClosed);
                            return;
                        }
                        finally
                        {
                            generator.lock_stop();
                            recvTimer.cancel();
                            _action.stop();
                            _namedRecvChan.close();
                            if (namedLost.has)
                            {
                                namedLost.msg._csp.close();
                                namedLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await _namedRecvChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg._csp.close();
                            }
                            foreach (var item in namedMap)
                            {
                                item.value2._csp.close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        byte[] sendHead = new byte[17];
                        Serializer serializer1 = new Serializer(new byte[sendHead.Length + buffSize], sendHead.Length, buffSize, _matchParamMember);
                        Serializer serializer2 = new Serializer(new byte[sendHead.Length + buffSize], sendHead.Length, buffSize, _matchParamMember);
                        wait_group sendBuffWg = new wait_group();
                        chan_lost_msg<SendBuffParam> sendBuffLost = new chan_lost_msg<SendBuffParam>();
                        chan_lost_msg<SendRequestParam> sendRequestLost = new chan_lost_msg<SendRequestParam>();
                        chan<SendBuffParam> sendBuffChan = chan<SendBuffParam>.make(1);
                        generator.children serializerChild = new generator.children();
                        serializerChild.go(async delegate ()
                        {
                            try
                            {
                                await generator.select().case_receive(sendReplyChan, async delegate (SendReplyParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            serializer1.Position = 0;
                                            len1 = serializer1.SerializeReply(param.reply);
                                            if (null != param.result)
                                            {
                                                try
                                                {
                                                    len2 = serializer1.Serialize(param.result) - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    serializer1.Position = 0;
                                                    len1 = serializer1.SerializeReply(new Reply { state = ReplyState.RemoteSerializeError });
                                                }
                                            }
                                        }
                                        catch (Exception)
                                        {
                                            SetCode(ExitCode.ReplySerializeError);
                                            throw;
                                        }
                                    });
                                    WriteHead(serializer1.Buffer, param.id, len1, len2, DataType.Reply);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref serializer1, ref serializer2);
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2 });
                                }).case_receive(sendRequestChan, async delegate (SendRequestParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    sendRequestLost.set(param);
                                    if (!await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            serializer1.Position = 0;
                                            len1 = serializer1.SerializeRequest(param.request);
                                            if (null != param.args && param.args.Length != 0)
                                            {
                                                try
                                                {
                                                    len2 = serializer1.Serialize(param.args) - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    recvReplyChan.post(new RecvReplyParam { id = param.id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalSerializeError } });
                                                    return false;
                                                }
                                            }
                                            return true;
                                        }
                                        catch (Exception)
                                        {
                                            SetCode(ExitCode.RequestSerializeError);
                                            throw;
                                        }
                                    }))
                                    {
                                        param.overSend?.Close();
                                        sendRequestLost.clear();
                                        return;
                                    }
                                    WriteHead(serializer1.Buffer, param.id, len1, len2, DataType.Request);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref serializer1, ref serializer2);
                                    sendRequestLost.clear();
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2, overSend = param.overSend });
                                }, lostMsg: sendRequestLost).loop();
                            }
                            catch (generator.stop_exception) { throw; }
                            catch (Exception) { }
                            finally
                            {
                                generator.lock_stop();
                                _action.stop();
                                if (sendRequestLost.has)
                                {
                                    sendRequestLost.msg.overSend?.Close();
                                    sendRequestLost.clear();
                                }
                                generator.unlock_stop();
                            }
                        });
                        try
                        {
                            chan<void_type> keepChan = chan<void_type>.make(1);
                            Action timerKeepHandler = keepChan.wrap_try_default();
                            Action timerSendHandler = delegate ()
                            {
                                SetCode(ExitCode.SendBinOvertime);
                                _action.stop();
                            };
                            if (_keep > 0)
                            {
                                sendTimer.interval(_keep / 2, timerKeepHandler);
                            }
                            await generator.select().case_receive(_remoteCmdChan, async delegate (DataType cmd)
                            {
                                WriteHead(sendHead, 0L, 0, 0, cmd);
                                switch (cmd)
                                {
                                    case DataType.NoKeep:
                                        _keep = -1;
                                        sendTimer.cancel();
                                        if (!recvBin)
                                        {
                                            recvTimer.cancel();
                                        }
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                            return;
                                        }
                                        break;
                                    case DataType.Close:
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                            return;
                                        }
                                        SetCode(ExitCode.LocalClose);
                                        _remoteCmdChan.close();
                                        WriteHead(sendHead, 0L, 0, 0, DataType.Keep);
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                            return;
                                        }
                                        await generator.hold();
                                        break;
                                }
                            }).case_receive(_cancelRpcChan, async delegate (long id)
                            {
                                WriteHead(sendHead, id, 0, 0, DataType.RequestCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                            }).case_receive(sendBuffChan, async delegate (SendBuffParam param)
                            {
                                param.overSend?.wg.force();
                                if (!await _socket.write(new ArraySegment<byte>(serializer2.Buffer, 0, param.count)))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBuffWg.done();
                            }, lostMsg: sendBuffLost).case_receive(_cancelSendChan, async delegate (SendName name)
                            {
                                if (name._done)
                                {
                                    return;
                                }
                                name._done = true;
                                WriteHead(sendHead, name._id, 0, 0, DataType.BinCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                            }).case_receive(_sendByteChan, async delegate (SendByteParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = true;
                                sendTimer.cancel();
                                if (param.deadline > 0)
                                {
                                    sendTimer.deadline(param.deadline, timerSendHandler);
                                }
                                socket_result result;
                                generator.lock_stop();
                                if (null != param.data)
                                {
                                    result = await _socket.write(new ArraySegment<byte>(param.data, (int)param.offset, param.count));
                                }
                                else if (null != param.file)
                                {
                                    result = await ((socket_tcp)_socket).send_file(param.file, param.offset, param.count);
                                }
                                else if (isTcp)
                                {
                                    result = await ((socket_tcp)_socket).write(param.pointer, param.offset, param.count);
                                }
                                else
                                {
                                    result = await ((socket_pipe)_socket).write(param.pointer, param.offset, param.count);
                                }
                                generator.unlock_stop();
                                if (!result)
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                                sendBin = false;
                                if (param.deadline > 0)
                                {
                                    sendTimer.cancel();
                                }
                                if (_keep > 0)
                                {
                                    sendTimer.interval(_keep / 2, timerKeepHandler);
                                }
                            }).case_receive(keepChan, async delegate ()
                            {
                                WriteHead(sendHead, 0L, 0, 0, DataType.Keep);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                    return;
                                }
                            }).loop();
                            SetCode(ExitCode.SocketClosed);
                        }
                        finally
                        {
                            generator.lock_stop();
                            await serializerChild.stop();
                            sendTimer.cancel();
                            _action.stop();
                            _sendByteChan.close();
                            _cancelRpcChan.close();
                            _cancelSendChan.close();
                            _remoteCmdChan.close();
                            sendBuffChan.close();
                            if (sendBuffLost.has)
                            {
                                sendBuffLost.msg.overSend?.Close();
                                sendBuffLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await sendBuffChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg.overSend?.Close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        mt19937 mt = new mt19937();
                        generator.children callChild = new generator.children();
                        ConcurrentDictionary<long, RpcCancel> rpcCancelDict = new ConcurrentDictionary<long, RpcCancel>();
                        while (true)
                        {
                            RecvRequestParam request = await recvRequestChan.receive();
                            OverRecv[] recvs = null;
                            if (null != request.request.sends)
                            {
                                RecvName[] sends = request.request.sends;
                                recvs = new OverRecv[sends.Length];
                                for (int i = 0; i < sends.Length; i++)
                                {
                                    if (!sends[i].Check())
                                    {
                                        SetCode(ExitCode.RecvBinError);
                                        _action.stop();
                                        return;
                                    }
                                    recvs[i] = new OverRecv(sends[i], this, new csp_chan<int, RecvParam>(_strands[0]), i == 0 ? null : recvs[i - 1]);
                                }
                            }
                            if (request.cancel)
                            {
                                if (rpcCancelDict.TryRemove(request.id, out RpcCancel rpcCancel))
                                {
                                    rpcCancel.wg.force();
                                }
                                if (null != recvs)
                                {
                                    callChild.free_go(_strands[0], () => DiscardRecv(recvs));
                                }
                                continue;
                            }
                            tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand> handler;
                            if (null == request.request.name || null == request.args || !_methods.Get(request.request.name, out handler))
                            {
                                sendReplyChan.post(new SendReplyParam { id = request.id, reply = new Reply { state = ReplyState.NotFound } });
                                if (null != recvs)
                                {
                                    callChild.free_go(_strands[0], () => DiscardRecv(recvs));
                                }
                            }
                            else
                            {
                                RpcCancel rpcCancel = new RpcCancel { wg = new wait_group(1, true) };
                                if (!rpcCancelDict.TryAdd(request.id, rpcCancel))
                                {
                                    sendReplyChan.post(new SendReplyParam { id = request.id, reply = new Reply { state = ReplyState.NotFound } });
                                    continue;
                                }
                                callChild.free_go(handler.value2 ?? _strands[1 == _strands.Length ? 0 : (1 + (int)((_strands.Length - 1) * mt.NextDouble()))], async delegate ()
                                {
                                    object result = null;
                                    Reply reply = new Reply();
                                    try
                                    {
                                        _session.value = this;
                                        _rpcCancel.value = rpcCancel;
                                        _recvList.value = new RecvList { recvs = recvs };
                                        async_result_wrap<object, ReplyState> resultWrap = new async_result_wrap<object, ReplyState>
                                        {
                                            value1 = request.fields,
                                            value2 = ReplyState.Success
                                        };
                                        await handler.value1(resultWrap, request.args);
                                        if ((reply.state = resultWrap.value2) == ReplyState.Success)
                                        {
                                            result = resultWrap.value1;
                                        }
                                    }
                                    catch (generator.stop_exception)
                                    {
                                        reply.state = ReplyState.Stopped;
                                        throw;
                                    }
                                    catch (CancelException)
                                    {
                                        reply.state = ReplyState.RemoteCancel;
                                    }
                                    catch (CastArgsException ec)
                                    {
                                        reply.state = ec.state;
                                    }
                                    catch (Exception ec)
                                    {
                                        reply.state = ReplyState.Exception;
                                        if (null != ec.InnerException)
                                        {
                                            Exception inner = ec.InnerException;
                                            reply.message = $"{inner.Message}\r\n{ec.Message}\r\n{inner.Source}\r\n{ec.Source}\r\n{inner.StackTrace}\r\n{ec.StackTrace}";
                                        }
                                        else
                                        {
                                            reply.message = $"{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}";
                                        }
                                    }
                                    finally
                                    {
                                        generator.lock_stop();
                                        await ClearCallback();
                                        if (rpcCancelDict.TryRemove(request.id, out var _) && request.request.reply)
                                        {
                                            sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                        }
                                        generator.children[] children = generator.all_children();
                                        if (children.Length > 0)
                                        {
                                            await generator.children.stop(children);
                                        }
                                        if (null != recvs)
                                        {
                                            for (int i = 0; i < recvs.Length && (int)ExitCode.Undefined == _exitCode; i++)
                                            {
                                                while (!recvs[i].Completed)
                                                {
                                                    csp_invoke_wrap<int> recvRes = await recvs[i].TimedRecv(_keep, _lostBinBuff, 0, _lostBinBuff.Length);
                                                    if (recvRes.state != chan_state.ok)
                                                    {
                                                        SetCode(ExitCode.RecvBinOvertime);
                                                        _action.stop();
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        generator.unlock_stop();
                                    }
                                });
                            }
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        while (true)
                        {
                            RecvReplyParam reply = await recvReplyChan.receive();
                            if (replyDict.TryGetValue(reply.id, out var replyPack))
                            {
                                replyDict.Remove(reply.id);
                                replyPack.timer?.cancel();
                                if (reply.state == ReplyState.Success)
                                {
                                    replyPack.result.complete(new Result { state = reply.reply.state, result = reply.result, message = reply.reply.message });
                                }
                                else
                                {
                                    replyPack.result.complete(new Result { state = reply.state });
                                }
                            }
                        }
                    });
                    while (true)
                    {
                        var rpc = await _rpcChan.wait(rpcLost);
                        if (rpc.state != chan_state.ok)
                        {
                            break;
                        }
                        long id = rpc.msg.id;
                        if (rpc.msg.timed > 0)
                        {
                            rpc.msg.request.reply = true;
                            async_timer timer = new async_timer();
                            replyDict.Add(id, new ReplyMapValue { timer = timer, result = rpc.result });
                            timer.timeout(rpc.msg.timed, () => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Overtime }));
                        }
                        else if (rpc.msg.timed < 0)
                        {
                            rpc.msg.request.reply = true;
                            replyDict.Add(id, new ReplyMapValue { result = rpc.result });
                        }
                        else
                        {
                            rpc.msg.request.reply = false;
                            rpc.complete(new Result { state = ReplyState.Success });
                        }
                        if (rpc.msg.request.reply)
                        {
                            rpc.msg.overCancel.wg?.async_wait(() => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.LocalCancel }));
                        }
                        sendRequestChan.post(new SendRequestParam { id = id, args = rpc.msg.args, request = rpc.msg.request, overSend = rpc.msg.overSend });
                    }
                }
                finally
                {
                    generator.lock_stop();
                    _socket.close();
                    await ioChild.stop();
                    _rpcChan.close();
                    sendRequestChan.close();
                    if (rpcLost.has)
                    {
                        rpcLost.msg.msg.overSend?.Close();
                        rpcLost.msg.fail();
                        rpcLost.clear();
                    }
                    foreach (var item in replyDict)
                    {
                        item.Value.timer?.cancel();
                        item.Value.result.fail();
                    }
                    while (true)
                    {
                        var wrap = await _rpcChan.wait();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                        wrap.fail();
                    }
                    while (true)
                    {
                        var wrap = await sendRequestChan.receive();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                    }
                    generator.unlock_stop();
                }
            }
        }
    }
}
